import copy
import os
from itertools import product
import random
from typing import List, Tuple
from combinations.conf import logger
import pyJianYingDraft as draft
from pyJianYingDraft import trange, Intro_type
from pyJianYingDraft.segment import Speed


def _update_segment_with_new_animation_and_speed(script, segment, new_material, speed_factor):
    """
    更新 segment：添加动画和速度调整，并清理已有的冲突效果。

    Args:
        script (draft.Script): 当前脚本对象
        segment (VideoSegment): 要修改的视频片段对象
        new_material (VideoMaterial): 新的视频素材
        speed_factor (float): 视频播放速度（例如 0.8 表示慢速）
    """
    # 计算时间范围（单位转换：纳秒 -> 秒）
    start_time = segment.target_timerange.start/ 1000000
    # 1/4的动画持续时间
    duration = segment.target_timerange.duration / 5000000

    # 创建新的视频片段（含速度设置）
    temp_segment = draft.Video_segment(
        new_material,
        target_timerange=trange(f"{start_time}", f"{duration}"),
        speed=speed_factor
    )

    # 随机选择一个入场动画
    random_intro = random.choice(list(Intro_type))
    temp_segment = temp_segment.add_animation(random_intro, duration=f"{duration}s")
    animation_id = temp_segment.animations_instance.animation_id
    logger.debug(f"生成动画ID: {animation_id}")

    # 设置当前 segment 的速度值
    speed_instance = Speed(speed_factor)
    segment.raw_data['speed'] = speed_factor

    # 清理已有冲突的 extra_material_refs（只保留一个动画、一个速度）
    _clean_extra_material_references(segment, script)

    # 添加新的动画和速度引用
    segment.raw_data['extra_material_refs'].append(animation_id)
    segment.raw_data['extra_material_refs'].append(speed_instance.global_id)

    # 将新动画和速度加入全局材料库
    script.materials.speeds.append(speed_instance)
    script.materials.animations.append(temp_segment.animations_instance)


def _clean_extra_material_references(segment, script):
    """
    清理 segment 中多余的 extra_material_refs 引用，防止冲突。

    Args:
        segment (VideoSegment): 要清理的视频片段
        script (draft.Script): 当前脚本对象
    """
    existing_refs = segment.raw_data.get('extra_material_refs', [])

    for ref_id in existing_refs[:]:  # 使用切片避免在遍历时修改列表
        # 动画冲突检测
        for animation in script.imported_materials.get('material_animations', []):
            if animation["id"] == ref_id:
                logger.debug("发现已有动画，移除旧动画引用")
                segment.raw_data['extra_material_refs'].remove(ref_id)

        # 速度冲突检测
        for speed in script.imported_materials.get('speeds', []):
            if speed["id"] == ref_id:
                logger.debug("发现已有速度设置，移除旧速度引用")
                segment.raw_data['extra_material_refs'].remove(ref_id)

        # # 蒙版冲突检测
        # for mask in script.imported_materials.get('masks', []):
        #     if mask["id"] == ref_id:
        #         logger.debug("发现已有蒙版，移除旧蒙版引用")
        #         segment.raw_data['extra_material_refs'].remove(ref_id)
        #
        # # 音轨映射冲突检测
        # for channel_map in script.imported_materials.get('sound_channel_mappings', []):
        #     if channel_map["id"] == ref_id:
        #         logger.debug("发现已有音轨映射，移除旧音轨映射引用")
        #         segment.raw_data['extra_material_refs'].remove(ref_id)
        #
        # # 人声分离冲突检测
        # for vocal_sep in script.imported_materials.get('vocal_separations', []):
        #     if vocal_sep["id"] == ref_id:
        #         logger.debug("发现已有背景音分离效果，移除旧引用")
        #         segment.raw_data['extra_material_refs'].remove(ref_id)
        #
        # # 响度冲突检测
        # for loudness in script.imported_materials.get('loudnesses', []):
        #     if loudness["id"] == ref_id:
        #         logger.debug("发现已有响度调节效果，移除旧引用")
        #         segment.raw_data['extra_material_refs'].remove(ref_id)


def get_files_in_folder(folder_path: str) -> List[str]:
    """获取指定文件夹中的所有文件"""
    try:
        files = [os.path.join(folder_path, f) for f in os.listdir(folder_path)
                 if os.path.isfile(os.path.join(folder_path, f))]
        return files
    except Exception as e:
        logger.error(f"获取文件夹 {folder_path} 中的文件失败: {str(e)}")
        return []


def generate_combinations(file_lists: List[List[str]], allow_duplicates: List[int], is_random: bool) -> List[Tuple]:
    """生成文件组合，先处理允许重复的组合，再与不允许重复的组合进行组合"""
    try:
        file_lists_shuffled = copy.deepcopy(file_lists)

        for sublist in file_lists_shuffled:
            if isinstance(sublist, list):
                random.shuffle(sublist)
        # 分离允许重复和不允许重复的文件夹
        duplicate_lists = [files for files, allow in zip(file_lists_shuffled, allow_duplicates) if allow == 1]

        logger.info(f"允许重复的组合 {len(duplicate_lists)} 种")

        non_duplicate_lists = [files for files, allow in zip(file_lists_shuffled, allow_duplicates) if allow == 0]
        logger.info(f"不允许重复的组合 {len(non_duplicate_lists)} 种")

        # 处理允许重复的组合（笛卡尔积）
        duplicate_combinations = list(product(*duplicate_lists)) if duplicate_lists else [()]
        logger.info(f"重复的组合 {len(duplicate_combinations)} 种组合")

        # 处理不允许重复的组合
        non_duplicate_combinations = []
        max_length = min(len(files) for files in non_duplicate_lists) if non_duplicate_lists else 0
        for i in range(max_length):
            combo = [files[i] if i < len(files) else None for files in non_duplicate_lists]
            non_duplicate_combinations.append(tuple(combo))
        if is_random:
            random.shuffle(non_duplicate_combinations)  # 随机打乱不允许重复的组合

        logger.info(f" {len(non_duplicate_combinations)} 种组合")

        # 如果允许重复的组合比不允许重复的组合多，截断允许重复的组合
        if len(duplicate_combinations) > len(non_duplicate_combinations) != 0:
            duplicate_combinations = duplicate_combinations[:len(non_duplicate_combinations)]

        # 如果不允许重复的组合比允许重复的组合多，循环使用允许重复的组合
        elif len(duplicate_combinations) < len(non_duplicate_combinations):
            duplicate_combinations_cycle = duplicate_combinations * (
                    len(non_duplicate_combinations) // len(duplicate_combinations))
            duplicate_combinations_cycle += duplicate_combinations[
                                            :len(non_duplicate_combinations) % len(duplicate_combinations)]
            duplicate_combinations = duplicate_combinations_cycle

        logger.info(f"重复的组合 {len(duplicate_combinations)} 种组合")

        logger.info(f"不重复的组合 {len(non_duplicate_combinations)} 种组合")

        # 将允许重复的组合与不允许重复的组合进行组合
        combinations = [duplicate_combo + non_duplicate_combo
                        for duplicate_combo, non_duplicate_combo in
                        zip(duplicate_combinations, non_duplicate_combinations)]
        if not non_duplicate_combinations:
            combinations = duplicate_combinations

        if is_random:
            random.shuffle(combinations)  # 随机打乱最终结果
        logger.info(f"预计可以生成 {len(combinations)} 种组合")
        return combinations
    except Exception as e:
        logger.error(f"生成组合失败: {str(e)}")
        return []
